/* plot.tcc */

#ifndef DODO_PLOT_TCC
#define DODO_PLOT_TCC

namespace dodo_plot
{
//Plot

//template<class Y_C_T, class Y_T>
//Plot::Plot(const Y_C_T<Y_T>& y, 
//	const Y_T& y_min, const Y_T& y_max
//	)
//	: data_p_(new Plot_Data<int, Y_T, Null_Proj_1D<int>, Null_Proj_1D<Y_T> >(y.begin(), y.end(), y_min, y_max))
//{
//}
//
//template<class X_C_T, class X_T, class Y_C_T, class Y_T>
//Plot::Plot(const X_C_T<X_T>& x, const Y_C_T<Y_T>& y, 
//	const X_T& x_min, const X_T& x_max,
//	const Y_T& y_min, const Y_T& y_max
//	)
//	: data_p_(new Plot_Data<X_T, Y_T, Null_Proj_1D<X_T>, Null_Proj_1D<Y_T> >(x.begin(), x.end(), y.begin(), x_min, x_max, y_min, y_max))
//{ }
		

template<class Y_Iter, class Y_T>
Plot::Plot(Y_Iter y_b, Y_Iter y_e, 
	const Y_T& y_min, const Y_T& y_max
	)
	: data_p_(new Plot_Data<int, Y_T, Null_Projector, Null_Projector>(y_b, y_e, y_min, y_max))
{ }
	
template<class X_Iter, class X_T, class Y_Iter, class Y_T>
Plot::Plot(X_Iter x_b, X_Iter x_e,
	Y_Iter y_b,
	const X_T& x_min, const X_T& x_max,
	const Y_T& y_min, const Y_T& y_max
	)
	: data_p_(new Plot_Data<X_T, Y_T, Null_Projector, Null_Projector>(x_b, x_e, y_b, x_min, x_max, y_min, y_max))
{ }
		


//Plot_Data<>

// 4 args
template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
template<class Y_Iter>
Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::Plot_Data(Y_Iter y_b, Y_Iter y_e,
	const Y_T& y_min, const Y_T& y_max)
	: y_(y_b, y_e), 
	x_proj_(null_projector), 
	y_proj_(null_projector),
	y_min_(y_min), y_max_(y_max),
	line_color_(color_name::BLACK),
	line_width_(1.0)
{
	int count = std::distance(y_b, y_e);
	for(int i = 0; i < count; ++i)
		x_.push_back(i);
	x_min_ = 0; 
	x_max_ = count - 1;
}

// 5 args
template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
template<class Y_Iter>
Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::Plot_Data(Y_Iter y_b, Y_Iter y_e,
	const Y_T& y_min, const Y_T& y_max,
	Y_Proj_T y_proj)
	: y_(y_b, y_e),
	x_proj_(null_projector),
	y_proj_(y_proj),
	y_min_(y_min), y_max_(y_max),
	line_color_(color_name::BLACK),
	line_width_(1.0)
{
	int count = std::distance(y_b, y_e);
	for(int i = 0; i < count; ++i)
		x_.push_back(i);
	x_min_ = 0;
	x_max_ = count - 1;
}

// 7 args
template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
template<class X_Iter, class Y_Iter>
Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::Plot_Data(X_Iter x_b, X_Iter x_e, Y_Iter y_b,
	const X_T& x_min, const X_T& x_max,
	const Y_T& y_min, const Y_T& y_max
	)
	: x_(x_b, x_e),
	x_proj_(null_projector),
	y_proj_(null_projector),
	x_min_(x_min), x_max_(x_max),
	y_min_(y_min), y_max_(y_max),
	line_color_(color_name::BLACK),
	line_width_(1.0)
{
	Y_Iter y_b_copy = y_b;
	std::advance(y_b, std::distance(x_b, x_e));
	y_.assign(y_b_copy, y_b);
}

// 9 args
template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
template<class X_Iter, class Y_Iter>
Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::Plot_Data(X_Iter x_b, X_Iter x_e, Y_Iter y_b,
	const X_T& x_min, const X_T& x_max,
	const Y_T& y_min, const Y_T& y_max,
	const X_Proj_T& x_proj,
	const Y_Proj_T& y_proj)
	: x_(x_b, x_e),
	x_proj_(x_proj),
	y_proj_(y_proj),
	x_min_(x_min), x_max_(x_max),
	y_min_(y_min), y_max_(y_max),
	line_color_(color_name::BLACK),
	line_width_(1.0)
{
	Y_Iter y_b_copy = y_b;
	std::advance(y_b, std::distance(x_b, x_e));
	y_.assign(y_b_copy, y_b);
}

template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
void Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::draw(
	const Plotter& plotter) const
{
	std::list<Point> point_list;

	typename std::list<X_T>::const_iterator x_iter = x_.begin();
	typename std::list<Y_T>::const_iterator y_iter = y_.begin();
	for( ; x_iter != x_.end(); ++x_iter, ++y_iter)
	{
		point_list.push_back(
			Point(x_proj_(*x_iter)
				, y_proj_(*y_iter))
			);
//		std::cout << x_proj_(*x_iter) << " ~ " << y_proj_(*y_iter) << std::endl;
	}

	plotter.save();
	plotter.begin_new_path();
	plotter.set_line_cap(LINE_CAP_ROUND);
	plotter.set_line_join(LINE_JOIN_ROUND);
	plotter.rectangle(Point(x_proj_(x_min_), y_proj_(y_min_)),
		Point(x_proj_(x_max_), y_proj_(y_max_)));
	plotter.clip();
	plotter.polyline(point_list.begin(),
		point_list.end());
	plotter.set_line_width(line_width_);
	plotter.set_color(line_color_);
	plotter.stroke();
	plotter.reset_clip();
	plotter.restore();
}

//template<class X_T, class Y_T>
//void Plot_Data<X_T, Y_T>::make_point_list(std::list<Point>& l) const
//{
//
//}

template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
void Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::set_line_color(const Color& color)
{
	line_color_ = color;
}

template<class X_T, class Y_T, class X_Proj_T, class Y_Proj_T>
void Plot_Data<X_T, Y_T, X_Proj_T, Y_Proj_T>::set_line_width(double width)
{
	line_width_ = width;
}


}

#endif // DODO_PLOT_TCC
